
package protocol.transactions;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import protocol.XoneProtocol;
import protocol.XoneServiceCode;
import protocol.meta.BindAccountRawInfo;
import protocol.meta.BindingAccountVO;
import android.database.Cursor;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import com.netease.http.THttpRequest;
import com.netease.pkgRelated.ErrorToString;
import com.netease.pkgRelated.XoneConsts.WB_ACC_SYNC_TYPE;
import com.netease.share.ShareBind;
import com.netease.share.ShareType;
import com.netease.share.db.ManagerShareBind;

public class SyncBindingInfoTrasaction extends XoneBaseTransaction {

    private static final byte STEP_DOWNLOAD = 0x01;
    private static final byte STEP_UPLOAD = 0x02;
    private byte mStep;
    private String mUserKey;
    private List<ShareBind> localUpdateList = new ArrayList<ShareBind>();
    private List<BindingAccountVO> serverUpdateList = new ArrayList<BindingAccountVO>();

    public SyncBindingInfoTrasaction(String userKey) {
        super(TRANSACTION_TYPE_SYNC_BIND_ACCOUNT);
        mStep = STEP_DOWNLOAD;
        mUserKey = userKey;
    }

    @Override
    public void onTransact() {
        THttpRequest request = null;
        switch (mStep) {
            case STEP_DOWNLOAD:
                request = XoneProtocol.getInstance().createGetBindingInfoRequest();
                break;
            case STEP_UPLOAD:
                request = XoneProtocol.getInstance().createUploadBindingInfoRequest(
                        serverUpdateList);
                break;
        }

        if (request != null) {
            sendRequest(request);
        } else {
            doEnd();
        }
    }

    @Override
    protected void onXoneTransactionSuccess(int code, Object obj) {
        if (obj != null && obj instanceof JsonElement) {
            if (mStep == STEP_DOWNLOAD) {
                List<BindingAccountVO> accList = null;
                try {
                  JsonElement list = ((JsonElement)obj).getAsJsonObject().get("list");
                   Gson gson = new Gson();
                   Type collectionType = new
                   TypeToken<List<BindingAccountVO>>(){}.getType();
                   accList = gson.fromJson(list, collectionType);

                  BindingAccountVO bind = null;
                  for(int i=0; i<accList.size(); i++){
                      bind = accList.get(i);
                      BindAccountRawInfo rawInfo = new BindAccountRawInfo(new JSONObject(bind.rawInfo));
                      bind.wbInfo = rawInfo;
                  }
              } catch (JSONException e) {
                  e.printStackTrace();
              }

                mergeBindAccountInfo(accList);
                if (serverUpdateList.size() > 0) {
                    mStep = STEP_UPLOAD;
                    getTransactionEngine().beginTransaction(this);
                } else {
                    updateLocalBindDb();
                    notifyMessage(XoneServiceCode.TRANSACTION_SUCCESS, null);
                }
            } else if (mStep == STEP_UPLOAD) {
                updateLocalBindDb();
                notifyMessage(XoneServiceCode.TRANSACTION_SUCCESS, null);
            }
        } else {
            notifyError(XoneServiceCode.ERR_CODE_DATA_PARSE_EXCEPTION,
                    ErrorToString.getString(XoneServiceCode.ERR_CODE_DATA_PARSE_EXCEPTION));
        }
    }

    private void mergeBindAccountInfo(List<BindingAccountVO> serverList) {
        Cursor cursor = ManagerShareBind.getAllShareBind(mUserKey);
        // Map<ShareType, ShareBind> map = new HashMap<ShareType, ShareBind>();
        List<ShareBind> localList = new ArrayList<ShareBind>();
        if (cursor != null && cursor.moveToFirst()) {
            do {
                ShareBind shareBind = new ShareBind(cursor, ShareBind.CURSOR_TYPE_DEFAULT);
                // map.put(shareBind.getShareType(), shareBind);
                localList.add(shareBind);
            } while (cursor.moveToNext());
        }
        if(cursor != null){
            cursor.close();
        }
        // List<ShareBind> localUpdateList = new ArrayList<ShareBind>();
        // List<BindingAccountVO> serverUpdateList = new
        // ArrayList<BindingAccountVO>();
        BindingAccountVO tempServer = null;
        ShareBind tempLocal = null;
        for (int i = serverList.size() - 1; i >= 0; i--) {
            tempServer = serverList.get(i);
            for (int j = localList.size() - 1; j >= 0; j--) {
                tempLocal = localList.get(j);
                if (tempServer.type == shareTypeToBindType(tempLocal.getShareType())) {
                    if (tempServer.timeDiff > tempLocal.getBindTime()) {// 服务端数据较新
                        if (tempServer.wbInfo != null) {
                            if (tempServer.wbInfo.ver == 2) {
                                ShareBind sb = new ShareBind(tempLocal.getShareType());
                                if (tempServer.wbInfo.uid != null) {// 版本相同，且为非删除状态,加到本地更新列表
                                    sb.setUserID(tempServer.wbInfo.uid);
                                    sb.setName(tempServer.wbInfo.nickname);
                                    sb.setProfile(tempServer.wbInfo.image_url);
                                    sb.setAccessToken(tempServer.wbInfo.token);
                                    sb.setDomainUrl(tempServer.wbInfo.profile_url);
                                    sb.setBindTime(tempServer.timeDiff);
                                } else {// 版本相同，且为删除状态，本地设置状态，同步成功后统一删除
                                    sb.setInvalid();
                                }
                                localUpdateList.add(sb);
                            } else {// 版本不同，不处理

                            }
                        }

                    } else if (tempServer.timeDiff < tempLocal.getBindTime()) {// 本地数据较新
                        BindingAccountVO bindServer = new BindingAccountVO();
                        bindServer.type = tempServer.type;
                        bindServer.timeDiff = tempLocal.getBindTime();
                        bindServer.wbInfo = new BindAccountRawInfo(null);
                        bindServer.wbInfo.ver = 2;
                        if (tempLocal.isValid()) {
                            bindServer.wbInfo.uid = tempLocal.getUserID();
                            bindServer.wbInfo.token = tempLocal.getAccessToken();
                            bindServer.wbInfo.nickname = tempLocal.getName();
                            bindServer.wbInfo.image_url = tempLocal.getProfile();
                            bindServer.wbInfo.profile_url = tempLocal.getDomainUrl();
                        }
                        serverUpdateList.add(bindServer);
                    }
                    serverList.remove(tempServer);
                    localList.remove(tempLocal);
                    break;
                }
            }
        }

        for (int i = 0; i < serverList.size(); i++) {
            tempServer = serverList.get(i);
            if (tempServer.wbInfo != null && tempServer.wbInfo.ver == 2
                    && tempServer.wbInfo.uid != null) {
                ShareBind sb = new ShareBind(bindTypeToShareType(tempServer.type));
                sb.setUserID(tempServer.wbInfo.uid);
                sb.setName(tempServer.wbInfo.nickname);
                sb.setProfile(tempServer.wbInfo.image_url);
                sb.setAccessToken(tempServer.wbInfo.token);
                sb.setDomainUrl(tempServer.wbInfo.profile_url);
                sb.setBindTime(tempServer.timeDiff);
                localUpdateList.add(sb);
            }
        }

        for (int i = 0; i < localList.size(); i++) {
            tempLocal = localList.get(i);
            BindingAccountVO bindServer = new BindingAccountVO();
            bindServer.type = shareTypeToBindType(tempLocal.getShareType());
            bindServer.timeDiff = tempLocal.getBindTime();
            bindServer.wbInfo = new BindAccountRawInfo(null);
            bindServer.wbInfo.ver = 2;
            if (tempLocal.isValid()) {
                bindServer.wbInfo.uid = tempLocal.getUserID();
                bindServer.wbInfo.token = tempLocal.getAccessToken();
                bindServer.wbInfo.nickname = tempLocal.getName();
                bindServer.wbInfo.image_url = tempLocal.getProfile();
                bindServer.wbInfo.profile_url = tempLocal.getDomainUrl();
                serverUpdateList.add(bindServer);
            }
        }
    }

    private void updateLocalBindDb() {
        ShareBind tempLocal = null;
        for (int i = 0; i < localUpdateList.size(); i++) {
            tempLocal = localUpdateList.get(i);
            ManagerShareBind.removeShareBind(mUserKey, tempLocal.getShareType());
            if (tempLocal.isValid()) {
                ManagerShareBind.addShareBind(mUserKey, tempLocal);
            }
        }
    }

    public int shareTypeToBindType(ShareType type) {
        int result = WB_ACC_SYNC_TYPE.WB_NETEASE;
        switch (type) {
            case Netease:
                result = WB_ACC_SYNC_TYPE.WB_NETEASE;
                break;
            case Sina:
                result = WB_ACC_SYNC_TYPE.WB_SINA;
                break;
            case Qqmblog:
                result = WB_ACC_SYNC_TYPE.WB_QQ;
                break;
            case Renren:
                result = WB_ACC_SYNC_TYPE.WB_RENREN;
                break;
            case Tencent:
                result = WB_ACC_SYNC_TYPE.WB_TENCENT;
                break;
        }
        return result;
    }

    public ShareType bindTypeToShareType(int type) {
        ShareType result = ShareType.Netease;
        switch (type) {
            case WB_ACC_SYNC_TYPE.WB_NETEASE:
                result = ShareType.Netease;
                break;
            case WB_ACC_SYNC_TYPE.WB_SINA:
                result = ShareType.Sina;
                break;
            case WB_ACC_SYNC_TYPE.WB_QQ:
                result = ShareType.Qqmblog;
                break;
            case WB_ACC_SYNC_TYPE.WB_RENREN:
                result = ShareType.Renren;
                break;
            case WB_ACC_SYNC_TYPE.WB_TENCENT:
                result = ShareType.Tencent;
                break;
        }
        return result;
    }
}
